# coding=UTF-8

import cgi
import wsgiref.handlers
import os
import re
import unicodedata

from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from django.template import Template
from google.appengine.ext.db import djangoforms

# We use http://code.google.com/p/gmemsess/ for session handling
import gmemsess

# This is our own file where all our models are defined
from models import *
# from plugins import *

# It's the only Request Handler used...
class MainPage(webapp.RequestHandler):
    
  def getpost(self):
  
    # I expect this to be one entry as we handle only single domains
    siteQuery = db.GqlQuery("SELECT * FROM Site")
    site = siteQuery.get()
    if not site:
      site = install()
    
    # the template values dictionary is passed to, guess what, the template
    template_name = 'index.html'
    template_values = {}
    template_values['site_name'] = site.title
    template_values['site_title'] = site.title
    
    # This is our session, where we store the messages
    self.session = gmemsess.Session(self)
    if self.session.is_new():
      self.session['message'] = ''
      self.session['title'] = ''
      self.session['text'] = ''
      self.session.save()
    template_values['message'] = self.session['message']
    self.session['message'] = ''
    self.session.save()
    
    # these are static currently...
    template_values['badhtmltags'] = 'banner button div form frame frameset head html input optgroup option select style textarea textflow title'
    template_values['semibadhtmltags'] = 'applet embed iframe object param script'
    
    # todo: put this in a plugin
    # also todo: make a plugin system available 
    # and make it modifiable 
    if site.googleanalytics:
      template_values['googleanalytics'] =  site.googleanalytics
    template_values['googleanalytics'] =  'UA-5833231-2'
    
    #path = os.path.join(os.path.dirname(__file__), 'static/')
    #os.path.walk(path, self.visit, "")
    
    # action controller
    action = getPath(self,1)
    
    # the operation as defined in the form (POST only)
    operation = self.request.get('operation')

    # current user
    user = getUser(self)

    # menu
    menu = []
    menu.append(getLoginLink(self)) # get the link to the login/logout page
    
    # menu.append([1,'/','Home',[[10,'/user','My Account']]]) #Test link
    menu.append([1,'/','Home']) #Test link
    if (user_access(self,user,"pageCreate")):
      menu.append([10,'/create','Write'])
    template_values['menu'] = createMenu(menu)
    
    # Get the current page, if available
    if getPath(self,2):
      pageQuery = db.GqlQuery("SELECT * FROM Page WHERE url_slug = :1", getPath(self,2))
      page = pageQuery.get()
      if page != None:
        if usermayeditpage(self, user, page):
          page.usermayedit = True
        else:
          page.usermayedit = False
        page.isnew = False  
    else:
      page = Page()
      page.usermayedit = True
      page.isnew = True

    # this is the action handler...
    # I use an if-elif-elif structure due to the lack of a proper switch in python...
    if action == 'user':
      template_values['userpage'] = 1
      template_values['user'] = user
      
    elif action == 'create':
      if (user_access(self,user,"pageCreate")):
        template_values['create_page'] = 1
        template_values['edit_page'] = page
        template_values['edit_page'].title = self.session['title'] 
        template_values['edit_page'].text = self.session['text']
        template_values['edit_page'].url_slug = ''
        template_name = 'index_edit.html'
        self.session['title'] = ''
        self.session['text'] = ''
        self.session.save()
      else:
        self.redirect('/')  
        
    elif action == 'edit' and page.usermayedit:
        template_values['edit_page'] = page
        template_name = 'index_edit.html'
    elif action == 'edit' and not page.usermayedit:
        self.redirect('/view/' + page.url_slug)
        
    elif action == 'view':
      template_values['view_page'] = 1
      if page:
        template_name = 'index_show.html'
        template_values['pages'] = [page]
        template_values['site_title'] = template_values['site_title'] + ' - ' + page.title
        
    elif action == 'post':
      if operation == 'Save' and page.usermayedit:
        page.author = user
        page.text = self.request.get('page_textarea')
        page.title = self.request.get('title')[0:499]
        if not page.url_slug:
          page.url_slug = uniquePageUrl(page.title)
          if page.url_slug == 'None':
            page.url_slug = ''
        if page.text and page.title:
          page.put()
          setMessage(self, 'Page saved!')
          self.redirect('/view/'+page.url_slug)
        else:
          self.session['title'] = page.title
          self.session['text'] = page.text
          self.session.save()
          setMessage(self, 'Please fill out all elements!')
          self.redirect('/create')
      if operation == 'Delete' and page.usermayedit:
        page.delete()
        setMessage(self, 'Page deleted!')
        self.redirect('/')
        
    else:
      template_name = 'index_show.html'
      template_values['view_all'] = 1
      # no action defined, so i show the main page
      page_query = Page.all().order('-date')
      howmany = page_query.count()
      pages = page_query.fetch(10)
      template_values['pages'] = pages

    path = os.path.join(os.path.dirname(__file__), 'templates/' + template_name)
    self.response.out.write(template.render(path, template_values))
  

  def get(self):
    self.getpost()

  def post(self):
    self.getpost()
    
    
  # TODO: REMOVE 
  def visit(self, arg, dirname, names):
    r = re.compile('.*\.svn.*')  
    if (not re.match(r, dirname)): 
      setMessage(self, dirname)
    for a in names:
      setMessage(self, a)
    
    
    
    
    
    
def setMessage(self, msg):
  """Use this to display a message to the user,
  For example: Your changes have been saved.
  Multiple messages will be appended to one another."""
  self.session['message'] = '<li>' + msg + '</li>' + self.session['message'] 
  self.session.save()

def usermayeditpage(self, user, page):
  return (user_access(self, user,"pageEdit") or user_access(self, user,"pageEditOwn") and page.author.user == user.user)

def user_access(self, user, permissionTitle):
  """Determine if the given user has the given permission in the RBAC"""
  if user:
    for rkey in user.roles:
      r = Role.get(rkey)
      # self.setMessage(r.title)
      for pkey in r.permissions:
        p = Permission.get(pkey)
        # self.setMessage(p.title)
        if p.title == permissionTitle:
          return True
  return False

def getUser(self):
  cu = users.get_current_user()
  if cu:
    user = db.Query(ExtendUser).filter("user = ", users.get_current_user()).get()
    if not user:
      user = ExtendUser()
      user.user = cu
      user.nick = cu.nickname()
      role = db.Query(Role).filter("title = ", "registeredUser").get()
      user.roles = [role.key()]
      if user.nick.find('@') >= 0:
        user.nick = user.nick[:user.nick.find('@')]
      if user.nick.find('.') >= 0:
        user.nick = user.nick[:user.nick.find('.')]
      user.put()
  else:
    user = db.Query(ExtendUser).filter("nick = ", "anonymous").get()
  return user


# Helper function to get the url to the login / logout page
def getLoginLink(self):
  if users.get_current_user():
    url = users.create_logout_url(self.request.uri)
    url_linktext = 'Logout'
  else:
    url = users.create_login_url(self.request.uri)
    url_linktext = 'Login'
  result = []
  result.append(100)
  result.append(url)
  result.append(url_linktext)
  return result


# Helper function to get the url to the login / logout page
def createMenu(menu):
  result = ''
  menu.sort()
  for menuitem in menu:
    result = result + '<li>'
    result = result + '<a href="'+menuitem[1]+'">'+menuitem[2]+'</a>'
    if len(menuitem) == 4:
      submenu = menuitem[3]
      result = result + '<ul>'+createMenu(submenu)+'</ul>'
      pass
    result = result + '</li>'
  return result


def getPath(self, i):
  path = self.request.path.split('/')
  if i > 0 and len(path) > i:
    result = path[i]
  else:
    result = False
  return result

def install():
  site = Site()
  site.title = 'abcomz'
  site.put()

  # Permissions
  pageView = Permission()
  pageView.title = 'pageView'
  pageView.put()
  pageCreate = Permission()
  pageCreate.title = 'pageCreate'
  pageCreate.put()
  pageEdit = Permission()
  pageEdit.title = 'pageEdit'
  pageEdit.put()
  pageEditOwn = Permission()
  pageEditOwn.title = 'pageEditOwn'
  pageEditOwn.put()
  pageDelete = Permission()
  pageDelete.title = 'pageDelete'
  pageDelete.put()

  # Preconfigured roles:
  anonymousRole = Role()
  anonymousRole.title = 'anonymous'
  anonymousRole.permissions = [pageView.key()]
  anonymousRole.put()
  registeredUser = Role()
  registeredUser.title = 'registeredUser'
  registeredUser.permissions = [pageCreate.key()]
  registeredUser.permissions.append(pageEditOwn.key())
  registeredUser.put()
  editor = Role()
  editor.title = 'editor'
  editor.permissions = [pageCreate.key(), pageEdit.key(), pageDelete.key()]
  editor.put()
  admin = Role()
  admin.title = 'admin'
  admin.put()

  # Preconfigured "user"
  anonymousUser = ExtendUser()
  anonymousUser.user = None
  anonymousUser.nick = 'anonymous'
  anonymousUser.roles = [anonymousRole.key()]
  anonymousUser.put()

  # return
  return site


def uniquePageUrl(title):
  """for a given title we return a unique url_slug for a new page"""
  uniquetitle = urlify(title)
  # check if this url is already taken...
  pageQuery = db.GqlQuery("SELECT * FROM Page WHERE url_slug = :1 ", uniquetitle)
  result = pageQuery.get()
  if result != None:
    found = False
    i = 0
    while not found:
      pageQuery = db.GqlQuery("SELECT * FROM Page WHERE url_slug = :1 ", uniquetitle + '-' + str(i))
      result2 = pageQuery.get()
      if result2 == None:
        found = True
        uniquetitle = uniquetitle + '-' + str(i)
      i = i + 1
  return uniquetitle

    
  
def urlify(value):
  """ this is a alternative version of djangos slugify, which takes unicode into account
  we map the german and danish umlaute chars to somewhat corresponding ascii-equivalents
  because the unicode decomposition in unicodedata.normalize doesn't do it very well"""
  value = unicode(value).lower()
  asciialternatives = {
    u'œ':u'oe',
    u'ø':u'oe',
    u'ß':u'ss',
    u'ö':u'oe',
    u'ü':u'ue',
    u'ä':u'ae',
    u'æ':u'ae',
    u'å':u'aa',
    }
  for k,v in asciialternatives.iteritems():
    value = value.replace(k, v)
  value = unicodedata.normalize('NFKD', value).encode('ascii','ignore')
  value = value.lower()
  value = re.sub('[^\w\s-]', '', value).strip()
  value = re.sub('[-\s]+', '-', value)
  return value





























def main():
  application = webapp.WSGIApplication(
                                       [(r'.*', MainPage)
                                       ],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
  main()
